/*
 * Copyright 2021 ZhongChao Blockchain Technology Research Institute.
 *
 * Copyright ConsenSys AG.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 *
 * This file has been modified by ZhongChao Blockchain Technology Research Institute to add support for Brochain.
 *
 * SPDX-License-Identifier: Apache-2.0
 */
package link.luyu.plugin.brochain.trie;

import static link.luyu.plugin.brochain.crypto.Hash.sm3;

import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.function.Consumer;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.hyperledger.besu.ethereum.rlp.RLP;

/** An Merkle Patricial Trie. */
public interface MerklePatriciaTrie<K, V> {

    Bytes EMPTY_TRIE_NODE = RLP.NULL;
    Bytes32 EMPTY_TRIE_NODE_HASH = Bytes32.wrap(sm3(EMPTY_TRIE_NODE.toArrayUnsafe()));;

    /**
     * Returns an {@code Optional} of value mapped to the hash if it exists; otherwise empty.
     *
     * @param key The key for the value.
     * @return an {@code Optional} of value mapped to the hash if it exists; otherwise empty
     */
    Optional<V> get(K key);

    /**
     * Returns value and ordered proof-related nodes mapped to the hash if it exists; otherwise
     * empty.
     *
     * @param key The key for the value.
     * @return value and ordered proof-related nodes
     */
    Proof<V> getValueWithProof(K key);

    /**
     * Updates the value mapped to the specified key, creating the mapping if one does not already
     * exist.
     *
     * @param key The key that corresponds to the value to be updated.
     * @param value The value to associate the key with.
     */
    void put(K key, V value);

    /**
     * Deletes the value mapped to the specified key, if such a value exists (Optional operation).
     *
     * @param key The key of the value to be deleted.
     */
    void remove(K key);

    /**
     * Returns the SM3 hash of the root node of the trie.
     *
     * @return The SM3 hash of the root node of the trie.
     */
    Bytes32 getRootHash();

    /**
     * Commits any pending changes to the underlying storage.
     *
     * @param nodeUpdater used to store the node values
     */
    void commit(NodeUpdater nodeUpdater);

    /**
     * Retrieve up to {@code limit} storage entries beginning from the first entry with hash equal
     * to or greater than {@code startKeyHash}.
     *
     * @param startKeyHash the first key hash to return.
     * @param limit the maximum number of entries to return.
     * @return the requested storage entries as a map of key hash to value.
     */
    Map<Bytes32, V> entriesFrom(Bytes32 startKeyHash, int limit);

    void visitAll(Consumer<Node<V>> nodeConsumer);

    CompletableFuture<Void> visitAll(
            Consumer<Node<V>> nodeConsumer, ExecutorService executorService);

    void visitLeafs(final TrieIterator.LeafHandler<V> handler);
}
